home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1997 / HAM Radio 1997.iso / vcls / rtf / rtf.pas next >
Pascal/Delphi Source File  |  1996-04-08  |  6KB  |  304 lines

  1. {Attached is an attempt at a Pascal RTF reader, which I abandoned in 
  2. favor of C. The approach is to treat RTF as a language and write
  3. a recursive descent parser for it. The C version works quite well.
  4.  
  5. The Pascal version may serve some simple purpose. It's yours to 
  6. use freely.}
  7.  
  8. program rtf;
  9. uses crt;
  10. const
  11.   BUFSIZE     = 1024;
  12.   BEGIN_CWORD = #$DC;
  13.   BEGIN_GROUP = #$FB;
  14.   END_GROUP   = #$FD;
  15.   TOKENSET    : set of char = [BEGIN_CWORD,BEGIN_GROUP,END_GROUP];
  16. var
  17.   current_ch   : char;
  18.   current_word : string[80];
  19.   current_parm : integer;
  20.   rtf_version  : integer;
  21.   rtf_charset  : string[8];
  22.   default_font : integer;
  23.   margin       : integer;
  24.   index        : integer;
  25.   buffer       : array [1..BUFSIZE] of char;
  26.   f            : file;
  27.   tagfile      : text;
  28.  
  29. procedure item; forward;
  30. procedure group; forward;
  31.  
  32. function o(ch: char) : char;
  33. begin
  34.   case ch of
  35.     BEGIN_GROUP: o := '{';
  36.     END_GROUP:   o := '}';
  37.     BEGIN_CWORD: o := '\';
  38.     else         o := ch;
  39.   end;
  40. end;
  41.  
  42. procedure getch;
  43. var
  44.   ch     : char;
  45.   result : integer;
  46.  
  47.   function nextch : char;
  48.   begin
  49.     if index >= BUFSIZE then
  50.     begin
  51.       BlockRead(f, buffer, BUFSIZE, result);
  52.  
  53.       if result = 0 then
  54.       begin
  55.           writeln('Unexpected end of RTF file');
  56.           halt;
  57.       end;
  58.       index := 0;
  59.     end;
  60.  
  61.     inc(index);
  62.     nextch := buffer[index];
  63.   end;
  64. begin
  65.   ch := nextch;
  66.   case ch of
  67.     '\':
  68.          begin
  69.            ch := nextch;
  70.            if ch in ['{','}','\'] then
  71.              current_ch := ch
  72.            else
  73.            begin
  74.              current_ch := BEGIN_CWORD;
  75.              dec(index);
  76.            end;
  77.          end;
  78.     '{': current_ch := BEGIN_GROUP;
  79.     '}': current_ch := END_GROUP;
  80.     else current_ch := ch;
  81.   end;
  82. end;
  83.  
  84. procedure accept(expected: char; echo: boolean);
  85. begin
  86.   if expected <> current_ch then
  87.   begin
  88.     writeln('SYNTAX: expected ',o(expected),' found ',o(current_ch));
  89.   end
  90.   else
  91.   begin
  92.     if echo and (current_ch in [' '..'~']+TOKENSET) then
  93.       write(o(current_ch));
  94.     getch;
  95.   end;
  96. end;
  97.  
  98. procedure accept_alpha(var alpha: string);
  99. begin
  100.   alpha := '';
  101.   while current_ch in ['A'..'Z','a'..'z'] do
  102.   begin
  103.     alpha := alpha + current_ch;
  104.     accept(current_ch, TRUE);
  105.   end;
  106. end;
  107.  
  108. procedure accept_num(var num: integer);
  109. var
  110.   value  : longint;
  111.   signed : boolean;
  112. begin
  113.   if current_ch = '-' then
  114.   begin
  115.     signed := TRUE;
  116.     accept('-',TRUE);
  117.   end
  118.   else
  119.     signed := FALSE;
  120.  
  121.   value := 0;
  122.   while current_ch in ['0'..'9'] do
  123.   begin
  124.     value := value*10 + ord(current_ch)-ord('0');
  125.     accept(current_ch, TRUE);
  126.   end;
  127.  
  128.   if value > 32767 then
  129.   begin
  130.     writeln('Integer overflow');
  131.     value := 32767;
  132.   end;
  133.  
  134.   if signed then
  135.     num := -value
  136.   else
  137.     num := value;
  138. end;
  139.  
  140. procedure control_word(var spelling: string; var parm: integer);
  141. begin
  142.   accept(BEGIN_CWORD,TRUE);
  143.   accept_alpha(spelling);
  144.   accept_num(parm);
  145.   if current_ch = ' ' then
  146.     accept(' ',TRUE);
  147.  
  148.   writeln(tagfile, spelling:10, parm:10);
  149. end;
  150.  
  151. procedure indent(amount: integer);
  152. var
  153.   i : integer;
  154. begin
  155.   inc(margin, amount);
  156.  
  157.   writeln;
  158.   for i:= 1 to margin do
  159.     write(' ');
  160. end;
  161.  
  162. procedure content;
  163. begin
  164.   indent(2);
  165.   accept(BEGIN_GROUP,TRUE);
  166.   indent(2);
  167.  
  168.   while current_ch <> END_GROUP do
  169.   begin
  170.     if current_ch = ';' then
  171.     begin
  172.       accept(current_ch, TRUE);
  173.       indent(0);
  174.     end
  175.     else if current_ch = BEGIN_GROUP then
  176.     begin
  177.       content;
  178.     end
  179.     else if current_ch = BEGIN_CWORD then
  180.     begin
  181.       item;
  182.     end
  183.     else
  184.       accept(current_ch, TRUE);
  185.   end;
  186.  
  187.   indent(-2);
  188.   accept(END_GROUP, TRUE);
  189.   indent(-2);
  190. end;
  191.  
  192. procedure item;
  193. begin
  194.   repeat
  195.     if current_ch = BEGIN_GROUP then
  196.     begin
  197.       content;
  198.     end
  199.     else if current_ch = ';' then
  200.     begin
  201.       accept(';', TRUE);
  202.       indent(0);
  203.     end
  204.     else
  205.     begin
  206.       while not (current_ch in [BEGIN_GROUP,END_GROUP,';']) do
  207.         accept(current_ch, TRUE);
  208.     end;
  209.   until not (current_ch in [BEGIN_GROUP,';',BEGIN_CWORD]);
  210. end;
  211.  
  212. procedure content1;
  213. var
  214.   alpha : string[80];
  215.   parm  : integer;
  216. begin
  217.   while (current_ch <> END_GROUP) do
  218.   begin
  219.     case current_ch of
  220.       BEGIN_GROUP:
  221.                    group;
  222.       BEGIN_CWORD:
  223.                    control_word(alpha, parm);
  224.       else
  225.       begin
  226.         {writeln('ERROR: unknown token: ',o(current_ch));}
  227.         accept(current_ch, TRUE);
  228.       end;
  229.     end;
  230.   end;
  231. end;
  232.  
  233. procedure group;
  234. begin
  235.   indent(2);
  236.   accept(BEGIN_GROUP, TRUE);
  237.   indent(2);
  238.  
  239.   content1;
  240.  
  241.   indent(-2);
  242.   accept(END_GROUP, TRUE);
  243.   indent(-2);
  244. end;
  245.  
  246. procedure version;
  247. var
  248.   alpha : string[80];
  249. begin
  250.   control_word(alpha, rtf_version);
  251.   if alpha <> 'rtf' then
  252.   begin
  253.     writeln('Not an RTF file');
  254.     halt;
  255.   end;
  256. end;
  257.  
  258. procedure character_set;
  259. var
  260.   parm : integer;
  261. begin
  262.   control_word(rtf_charset, parm);
  263. end;
  264.  
  265. procedure rtfile;
  266. begin
  267.   accept(BEGIN_GROUP, TRUE);
  268.   indent(2);
  269.  
  270.   version;
  271.   character_set;
  272.  
  273.   content1;
  274.  
  275.   indent(-2);
  276.   accept(END_GROUP, TRUE);
  277. end;
  278.  
  279. begin
  280.   ClrScr;
  281.   margin := 0;
  282.  
  283.   assign(f, ParamStr(1));
  284.   reset(f, 1);
  285.   assign(output, '');
  286.   rewrite(output);
  287.   assign(tagfile, 'tagfile.dat');
  288.   rewrite(tagfile);
  289.  
  290.   index  := BUFSIZE;
  291.   getch;
  292.  
  293.   rtfile;
  294. end.
  295.  
  296. +-------------------------------------------------+
  297. |  John Day
  298. |  Computer Science Innovations,Inc
  299. |  Principal Engineer    PHONE: (407) 676-2923 ext:410
  300. |  Melbourne, Fl    FAX: (407) 676-3255
  301. |              WWW:   http://www.csihq.com
  302. |              EMAIL: jday@csihq.com
  303. +--------------------------------------------------+
  304.